package me.xiaolei.andlog.impls

import me.xiaolei.andlog.ILog
import me.xiaolei.andlog.comm.InterceptorChain
import me.xiaolei.andlog.comm.LogType
import me.xiaolei.andlog.interceptor.impls.DiskInterceptor
import me.xiaolei.andlog.interceptor.IInterceptor
import me.xiaolei.andlog.interceptor.impls.LogInterceptor
import me.xiaolei.andlog.prints.impls.DefPrint
import me.xiaolei.andlog.prints.Print
import me.xiaolei.andlog.prints.impls.ThrowablePrint
import me.xiaolei.andlog.thread_pool.LogThreadPool
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.LinkedBlockingQueue
import kotlin.reflect.KClass

object LogImpl : ILog, Runnable
{
    private val executor by lazy { LogThreadPool.pool }
    private val chainQueue = LinkedBlockingQueue<InterceptorChain>(1024 * 8)
    private val keyWords = arrayOf("HTC_RIL", "RIL", "IMS", "AT", "GSM", "STK", "CDMA", "PHONE", "SMS")
    private val interceptorQueue = LinkedList<IInterceptor>()
    private val printMap = object : ConcurrentHashMap<KClass<out Any>, Print<out Any>>()
    {
        fun isKeyOrChild(msg: Any): Print<out Any>?
        {
            if (this.containsKey(msg::class))
                return this[msg::class]
            for ((kClass, print) in this)
            {
                if (kClass.isInstance(msg))
                    return print
            }
            return null
        }
    }

    init
    {
        // 添加内置的处理流程
        addInterceptor(LogInterceptor)
        addInterceptor(DiskInterceptor)
        executor.execute(this)
        // 添加内置的数据输出处理方案
        addPrint(Throwable::class, ThrowablePrint::class)
    }

    override fun d(tag: String, msg: Any?)
    {
        val chain = createInterceptorChain(LogType.DEBUG, tag, msg)
        chainQueue.offer(chain)
    }

    override fun d(tag: String, pattern: String, vararg args: Any)
    {
        val chain = createInterceptorChain(LogType.DEBUG, tag, String.format(Locale.CHINA, pattern, *args))
        chainQueue.offer(chain)
    }

    override fun e(tag: String, msg: Any?)
    {
        val chain = createInterceptorChain(LogType.ERROR, tag, msg)
        chainQueue.offer(chain)
    }

    override fun e(tag: String, pattern: String, vararg args: Any)
    {
        val chain = createInterceptorChain(LogType.ERROR, tag, String.format(Locale.CHINA, pattern, *args))
        chainQueue.offer(chain)
    }

    override fun i(tag: String, msg: Any?)
    {
        val chain = createInterceptorChain(LogType.INFO, tag, msg)
        chainQueue.offer(chain)
    }

    override fun i(tag: String, pattern: String, vararg args: Any)
    {
        val chain = createInterceptorChain(LogType.INFO, tag, String.format(Locale.CHINA, pattern, *args))
        chainQueue.offer(chain)
    }

    override fun v(tag: String, msg: Any?)
    {
        val chain = createInterceptorChain(LogType.VERBOSE, tag, msg)
        chainQueue.offer(chain)
    }

    override fun v(tag: String, pattern: String, vararg args: Any)
    {
        val chain = createInterceptorChain(LogType.VERBOSE, tag, String.format(Locale.CHINA, pattern, *args))
        chainQueue.offer(chain)
    }

    override fun w(tag: String, msg: Any?)
    {
        val chain = createInterceptorChain(LogType.WARNING, tag, msg)
        chainQueue.offer(chain)
    }

    override fun w(tag: String, pattern: String, vararg args: Any)
    {
        val chain = createInterceptorChain(LogType.WARNING, tag, String.format(Locale.CHINA, pattern, *args))
        chainQueue.offer(chain)
    }

    override fun run()
    {
        while (true)
        {
            try
            {
                val chain = chainQueue.take()
                chain.proceed()
            } catch (e: Exception)
            {
                e.printStackTrace()
                continue
            }
        }
    }

    // 检查key是否包含关键字的任意一个,并且生成对应的Chain
    private fun createInterceptorChain(type: LogType, tag: String, msg: Any?): InterceptorChain
    {
        for (word in keyWords)
        {
            if (tag.contains(word, true))
            {
                throw RuntimeException("tag contains sensitive word")
            }
        }
        val iterator = interceptorQueue.iterator()
        val print = when (msg)
        {
            null -> DefPrint
            else -> printMap.isKeyOrChild(msg::class) ?: DefPrint
        }

        val chain = InterceptorChain(
            type,
            tag,
            msg,
            print as Print<Any?>,
            iterator
        )

        return chain
    }

    /**
     * 添加拦截器
     */
    fun addInterceptor(interceptor: IInterceptor)
    {
        interceptorQueue.offer(interceptor)
    }

    /**
     * 添加一个输出实现类
     */
    fun <T : Any> addPrint(klass: KClass<T>, printKlass: KClass<out Print<T>>)
    {
        val javaKlass = printKlass.java
        val constructor = javaKlass.getConstructor()
        printMap[klass] = constructor.newInstance()
    }
}